﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Reflection;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Xml;
using SHomeWorkshop.LunarConcept.Tools;

namespace SHomeWorkshop.LunarConcept.Dialogs
{
    /// <summary>
    /// BuildMarkLines.xaml 的交互逻辑
    /// </summary>
    public partial class BuildMarkLines : Window
    {
        public BuildMarkLines(Widgets.StraitLineWidget sw)
        {
            InitializeComponent();

            if (sw == null) BtnBuild.IsEnabled = false;

            destStraitLineWidget = sw;

            if (sw.StartPoint.X != sw.EndPoint.X &&
                sw.StartPoint.Y != sw.EndPoint.Y)
            {
                BtnBuild.IsEnabled = false;//必须水平或垂直才允许添加刻度。
            }

            string defForeColorName = "Black";
            if (destStraitLineWidget != null)
            {
                defForeColorName = BrushManager.GetName(destStraitLineWidget.WidgetForeColor);
            }

            //利用反射取出Brushe类支持的所有色彩，填充到色彩选定框中。
            Type type = typeof(Brushes);
            PropertyInfo[] properties = type.GetProperties();
            foreach (PropertyInfo pi in properties)
            {
                DocumentOptionsDialog.BrushItem bi2 = new DocumentOptionsDialog.BrushItem(pi.GetValue(null, null) as Brush, pi.Name);
                CbxLineForeColor.Items.Add(bi2);

                if (bi2.BrushName == defForeColorName)
                {
                    CbxLineForeColor.SelectedItem = bi2;
                }
            }

            int destLineWidth = (int)destStraitLineWidget.WidgetLineWidth - 1;
            CbxLineWidth.SelectedIndex = (destLineWidth < 0 ? 0 : 
                (destLineWidth >= CbxLineWidth.Items.Count ? CbxLineWidth.Items.Count - 1 : destLineWidth));

            //不能在Xaml中挂接，容易出错。因为可能还未实例化影响到的部件。
            RBtnAutoPageWidthOrHeight.Checked += new RoutedEventHandler(RBtnAutoPageWidthOrHeight_Checked);
            RBtnCustomLength.Checked += new RoutedEventHandler(RBtnCustomLength_Checked);

            TbxMarkTextLines.Focus();
        }

        private Widgets.StraitLineWidget destStraitLineWidget;
        /// <summary>
        /// [只读]要画刻度的直线部件。必须为水平或垂直。
        /// </summary>
        public Widgets.StraitLineWidget DestStraitLineWidget
        {
            get { return destStraitLineWidget; }
        }

        private void RBtnAutoPageWidthOrHeight_Checked(object sender, RoutedEventArgs e)
        {
            TbxCustomLength.IsEnabled = false;

            RBtnCustomLength.IsChecked = false;
        }

        private void RBtnCustomLength_Checked(object sender, RoutedEventArgs e)
        {
            TbxCustomLength.IsEnabled = true;

            RBtnAutoPageWidthOrHeight.IsChecked = false;
        }

        private void BtnCancel_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void BtnBuild_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;

            if (destStraitLineWidget == null)
            {
                this.Close();
                return;
            }

            //至少两个刻度，因此，只有一行是不成的。

            string srcText = TbxMarkTextLines.Text;

            srcText = srcText.Replace("\r\n", "\n");
            char[] splitter = new char[1];
            splitter[0] = '\n';

            string[] lines = srcText.Split(splitter, StringSplitOptions.None);

            if (lines.Length < 2)
            {
                MessageBox.Show("　　至少需要两行刻度文本，否则没有意义。", Globals.AppName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            int paddingCount = lines.Length - 1;
            double padding = 0;

            bool drawVerticalMarks = false;

            if (destStraitLineWidget.StartPoint.X == destStraitLineWidget.EndPoint.X)
            {
                padding = Math.Abs(destStraitLineWidget.EndPoint.Y - destStraitLineWidget.StartPoint.Y) / paddingCount;
                drawVerticalMarks = false;//基线为纵向，需要横向刻度线。
            }
            else if (destStraitLineWidget.StartPoint.Y == destStraitLineWidget.EndPoint.Y)
            {
                padding = Math.Abs(destStraitLineWidget.EndPoint.X - destStraitLineWidget.StartPoint.X) / paddingCount;
                drawVerticalMarks = true;//基本为横向，需要纵向刻度线。
            }

            if (padding <= 4)
            {
                MessageBox.Show("　　基准直线部件太短，无法自动生成这些刻度。", Globals.AppName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            double lineLength = -1;//两个画线方法中，-1表示对齐到页面宽（或高）。

            if (RBtnCustomLength.IsChecked == true)
            {
                try
                {
                    lineLength = double.Parse(TbxCustomLength.Text);
                    if (lineLength < 10)
                    {
                        MessageBox.Show("　　刻度线长度框中的数字不能小于10。", Globals.AppName,
                           MessageBoxButton.OK, MessageBoxImage.Warning);
                        return;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("　　刻度线长度框中的数据格式有误，无法转换为数字。\r\n　　异常信息如下：" +
                        ex.Message + ex.StackTrace, Globals.AppName,
                       MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }
            }

            ModifingInfo info = new ModifingInfo() { ModifingDescription = "生成刻度线" };
            ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);
            destStraitLineWidget.MasterEditor.MasterManager.GetSelectedPageEditorStatus(info);
            destStraitLineWidget.MasterEditor.MasterManager.GetSelectedWidgetStatus_Old(info);
            destStraitLineWidget.MasterEditor.MasterManager.GetSelectedWidgetStatus_New(info);

            if (destStraitLineWidget.LayerIndex != Enums.WidgetLayerIndex.Background)
            {
                Action actLayerIndex = new Action(destStraitLineWidget.MasterEditor.Id, destStraitLineWidget.Id,
                    destStraitLineWidget.GetType().Name, XmlTags.LayerIndexTag, destStraitLineWidget.LayerIndex.ToString(),
                    Enums.WidgetLayerIndex.Background.ToString());
                destStraitLineWidget.LayerIndex = Enums.WidgetLayerIndex.Background;
                mi.AddAction(actLayerIndex);
            }

            if (drawVerticalMarks)
            {
                BuildVerticalMarkLines(lines, padding, lineLength, mi);
            }
            else
            {
                BuildHorizontalMarkLines(lines, padding, lineLength, mi);
            }

            this.Close();
        }

        enum Location { LeftOrTop, RightOrBottom }

        private double LineWidth
        {
            get
            {
                double lineWidth = 2;
                if (CbxLineWidth.SelectedItem != null)
                {
                    ComboBoxItem ciLineWidth = CbxLineWidth.SelectedItem as ComboBoxItem;
                    lineWidth = double.Parse(ciLineWidth.Tag as string);
                }
                return lineWidth;
            }
        }

        private LineDashType.DashType LineDash
        {
            get
            {
                if (CbxLineType.SelectedItem == null) return LineDashType.DashType.Solid;

                LineDashType.DashType type = (LineDashType.DashType)Enum.Parse(typeof(LineDashType.DashType),
                    ((CbxLineType.SelectedItem as ComboBoxItem).Tag as string));
                return type;
            }
        }

        /// <summary>
        /// 画一系列横向刻度线。
        /// </summary>
        private void BuildHorizontalMarkLines(string[] texts, double padding, double markLineLength, ModifingItem<Action, ModifingInfo> mi)
        {
            if (texts.Length < 2) return;
            if (mi == null) return;
            if (destStraitLineWidget == null) return;

            double baseOffset = destStraitLineWidget.TopLeft.Y;

            Location location = Location.LeftOrTop;
            if (RBtnLeftOrTop.IsChecked == true)
            {
                location = Location.LeftOrTop;
            }
            else if (RBtnRightOrBottom.IsChecked == true)
            {
                location = Location.RightOrBottom;
            }

            Brush foreColor = destStraitLineWidget.WidgetForeColor;

            DocumentOptionsDialog.BrushItem bi = CbxLineForeColor.SelectedItem as DocumentOptionsDialog.BrushItem;
            if (bi != null)
            {
                foreColor = BrushManager.GetBrushByEnglishName(bi.BrushName);
            }

            bool isLocked = (CkxLockLines.IsChecked == true);
            double lineWidth = this.LineWidth;
            LineDashType.DashType dash = this.LineDash;

            foreach (string s in texts)
            {
                XmlNode newLineNode = destStraitLineWidget.MasterEditor.WidgetSetNode.AppendXmlAsChild(
                    Properties.Resources.StraitLineXml);
                Widgets.StraitLineWidget sw = new Widgets.StraitLineWidget(destStraitLineWidget.MasterEditor);
                sw.XmlData = newLineNode;
                sw.NewID();
                sw.WidgetForeColor = foreColor;
                sw.WidgetLineWidth = lineWidth;
                sw.LineDash = dash;
                sw.IsLocked = isLocked;
                sw.LayerIndex = Enums.WidgetLayerIndex.Background;

                if (RBtnAutoPageWidthOrHeight.IsChecked == true)
                {
                    switch (location)
                    {
                        case Location.RightOrBottom:
                            {
                                sw.StartPoint = new Point(destStraitLineWidget.StartPoint.X - 10, baseOffset);
                                sw.EndPoint = new Point(destStraitLineWidget.MasterEditor.EditArea.Right, baseOffset);//刻度线在基线左侧
                                break;
                            }
                        case Location.LeftOrTop:
                            {
                                sw.StartPoint = new Point(destStraitLineWidget.StartPoint.X + 10, baseOffset);
                                sw.EndPoint = new Point(destStraitLineWidget.MasterEditor.EditArea.Left, baseOffset);//刻度线在基线右侧
                                break;
                            }
                    }
                }
                else//定长。
                {
                    switch (location)
                    {
                        case Location.LeftOrTop:
                            {
                                sw.StartPoint = new Point(destStraitLineWidget.StartPoint.X, baseOffset);
                                sw.EndPoint = new Point(sw.StartPoint.X - markLineLength, baseOffset);//刻度线在基线左侧
                                break;
                            }
                        case Location.RightOrBottom:
                            {
                                sw.StartPoint = new Point(destStraitLineWidget.StartPoint.X, baseOffset);
                                sw.EndPoint = new Point(sw.StartPoint.X + markLineLength, baseOffset);//刻度线在基线右侧
                                break;
                            }
                    }
                }

                sw.Arrows = Enums.ArrowType.None;
                sw.IsSelected = true;

                destStraitLineWidget.MasterEditor.AddWidget(sw);

                Action act = new Action(ActionType.WidgetAdded, destStraitLineWidget.MasterEditor.Id, sw.Id, null, sw.XmlData.OuterXml);
                mi.AddAction(act);

                if (s != null && s.Length > 0)
                {
                    XmlNode newTextAreaNode = destStraitLineWidget.MasterEditor.WidgetSetNode.AppendXmlAsChild(
                        "<Widget Type=\"TextArea\"><ParagraphSet xml:space=\"preserve\"><Paragraph><Text>" + s +
                        "</Text></Paragraph></ParagraphSet></Widget>");
                    Widgets.TextArea tw = new Widgets.TextArea(destStraitLineWidget.MasterEditor);
                    tw.XmlData = newTextAreaNode;
                    tw.NewID();
                    tw.WidgetLineWidth = 0;
                    tw.WidgetPadding = new Thickness(0);
                    tw.WidgetForeColor = foreColor;
                    tw.IsLocked = isLocked;
                    tw.LayerIndex = Enums.WidgetLayerIndex.Background;

                    destStraitLineWidget.MasterEditor.AddWidget(tw);
                    tw.InvalidateArrange(); tw.UpdateLayout();

                    if (RBtnAutoPageWidthOrHeight.IsChecked == true)
                    {
                        switch (location)
                        {
                            case Location.LeftOrTop:
                                {
                                    tw.Location = new Point(destStraitLineWidget.StartPoint.X + 10,
                                        sw.EndPoint.Y - tw.RealRect.Height / 2);//刻度线在基线左侧
                                    break;
                                }
                            case Location.RightOrBottom:
                                {
                                    tw.Location = new Point(destStraitLineWidget.StartPoint.X - 10 - tw.RealRect.Width,
                                        sw.EndPoint.Y - tw.RealRect.Height / 2);//刻度线在基线右侧
                                    break;
                                }
                        }
                    }
                    else//定长。
                    {
                        switch (location)
                        {
                            case Location.LeftOrTop:
                                {
                                    tw.Location = new Point(sw.EndPoint.X - tw.RealRect.Width,
                                        sw.EndPoint.Y - tw.RealRect.Height / 2);//刻度线在基线左侧
                                    break;
                                }
                            case Location.RightOrBottom:
                                {
                                    tw.Location = new Point(sw.EndPoint.X,
                                        sw.EndPoint.Y - tw.RealRect.Height / 2);//刻度线在基线右侧
                                    break;
                                }
                        }
                    }

                    tw.IsSelected = true;

                    Action actAddTw = new Action(ActionType.WidgetAdded, destStraitLineWidget.MasterEditor.Id, tw.Id, null, tw.XmlData.OuterXml);
                    mi.AddAction(actAddTw);
                }

                baseOffset += padding;
            }

            if (destStraitLineWidget.IsLocked != isLocked)
            {
                Action actLock = new Action(destStraitLineWidget.MasterEditor.Id, destStraitLineWidget.Id,
                    destStraitLineWidget.GetType().Name, XmlTags.IsLockedTag, destStraitLineWidget.IsLocked.ToString(), isLocked.ToString());
                destStraitLineWidget.IsLocked = isLocked;
                mi.AddAction(actLock);
            }

            destStraitLineWidget.MasterEditor.MasterManager.RegisterModifingItem(mi);
        }

        /// <summary>
        /// 画一系列纵向刻度线。
        /// </summary>
        private void BuildVerticalMarkLines(string[] texts, double padding, double markLineLength, ModifingItem<Action, ModifingInfo> mi)
        {
            if (texts.Length < 2) return;
            if (mi == null) return;
            if (destStraitLineWidget == null) return;

            double baseOffset = destStraitLineWidget.TopLeft.X;

            Location location = Location.LeftOrTop;
            if (RBtnLeftOrTop.IsChecked == true)
            {
                location = Location.LeftOrTop;
            }
            else if (RBtnRightOrBottom.IsChecked == true)
            {
                location = Location.RightOrBottom;
            }

            Brush foreColor = destStraitLineWidget.WidgetForeColor;

            DocumentOptionsDialog.BrushItem bi = CbxLineForeColor.SelectedItem as DocumentOptionsDialog.BrushItem;
            if (bi != null)
            {
                foreColor = BrushManager.GetBrushByEnglishName(bi.BrushName);
            }

            bool isLocked = (CkxLockLines.IsChecked == true);
            double lineWidth = this.LineWidth;
            LineDashType.DashType dash = this.LineDash;

            foreach (string s in texts)
            {
                XmlNode newLineNode = destStraitLineWidget.MasterEditor.WidgetSetNode.AppendXmlAsChild(
                    Properties.Resources.StraitLineXml);
                Widgets.StraitLineWidget sw = new Widgets.StraitLineWidget(destStraitLineWidget.MasterEditor);
                sw.XmlData = newLineNode;
                sw.NewID();
                sw.WidgetForeColor = foreColor;
                sw.WidgetLineWidth = lineWidth;
                sw.LineDash = dash;
                sw.IsLocked = isLocked;
                sw.LayerIndex = Enums.WidgetLayerIndex.Background;

                if (RBtnAutoPageWidthOrHeight.IsChecked == true)
                {
                    switch (location)
                    {
                        case Location.RightOrBottom:
                            {
                                sw.StartPoint = new Point(baseOffset, destStraitLineWidget.StartPoint.Y - 10);
                                sw.EndPoint = new Point(baseOffset, destStraitLineWidget.MasterEditor.EditArea.Bottom);//刻度线在基线左侧
                                break;
                            }
                        case Location.LeftOrTop:
                            {
                                sw.StartPoint = new Point(baseOffset, destStraitLineWidget.StartPoint.Y + 10);
                                sw.EndPoint = new Point(baseOffset, destStraitLineWidget.MasterEditor.EditArea.Left);//刻度线在基线右侧
                                break;
                            }
                    }
                }
                else//定长。
                {
                    switch (location)
                    {
                        case Location.LeftOrTop:
                            {
                                sw.StartPoint = new Point(baseOffset, destStraitLineWidget.StartPoint.Y);
                                sw.EndPoint = new Point(baseOffset, sw.StartPoint.Y - markLineLength);
                                break;
                            }
                        case Location.RightOrBottom:
                            {
                                sw.StartPoint = new Point(baseOffset, destStraitLineWidget.StartPoint.Y);
                                sw.EndPoint = new Point(baseOffset, sw.StartPoint.Y + markLineLength);
                                break;
                            }
                    }
                }

                sw.Arrows = Enums.ArrowType.None;
                sw.IsSelected = true;

                destStraitLineWidget.MasterEditor.AddWidget(sw);

                Action act = new Action(ActionType.WidgetAdded, destStraitLineWidget.MasterEditor.Id, sw.Id, null, sw.XmlData.OuterXml);
                mi.AddAction(act);

                if (s != null && s.Length > 0)
                {
                    XmlNode newTextAreaNode = destStraitLineWidget.MasterEditor.WidgetSetNode.AppendXmlAsChild(
                        "<Widget Type=\"TextArea\"><ParagraphSet xml:space=\"preserve\"><Paragraph><Text>" + s +
                        "</Text></Paragraph></ParagraphSet></Widget>");
                    Widgets.TextArea tw = new Widgets.TextArea(destStraitLineWidget.MasterEditor);
                    tw.XmlData = newTextAreaNode;
                    tw.NewID();
                    tw.WidgetLineWidth = 0;
                    tw.WidgetPadding = new Thickness(0);
                    tw.WidgetForeColor = foreColor;
                    tw.IsLocked = isLocked;
                    tw.LayerIndex = Enums.WidgetLayerIndex.Background;

                    destStraitLineWidget.MasterEditor.AddWidget(tw);
                    tw.InvalidateArrange(); tw.UpdateLayout();

                    if (RBtnAutoPageWidthOrHeight.IsChecked == true)
                    {
                        switch (location)
                        {
                            case Location.LeftOrTop:
                                {
                                    tw.Location = new Point(sw.EndPoint.X - tw.RealRect.Width / 2,
                                    destStraitLineWidget.StartPoint.Y + 10);
                                    break;
                                }
                            case Location.RightOrBottom:
                                {
                                    tw.Location = new Point(sw.EndPoint.X - tw.RealRect.Width / 2,
                                        destStraitLineWidget.StartPoint.Y - 10 - tw.RealRect.Height);
                                    break;
                                }
                        }
                    }
                    else//定长。
                    {
                        switch (location)
                        {
                            case Location.LeftOrTop:
                                {
                                    tw.Location = new Point(sw.EndPoint.X - tw.RealRect.Width / 2,
                                        sw.EndPoint.Y - tw.RealRect.Height);
                                    break;
                                }
                            case Location.RightOrBottom:
                                {
                                    tw.Location = new Point(sw.EndPoint.X - tw.RealRect.Width / 2,
                                        sw.EndPoint.Y);
                                    break;
                                }
                        }
                    }

                    tw.IsSelected = true;

                    Action actAddTw = new Action(ActionType.WidgetAdded, destStraitLineWidget.MasterEditor.Id, tw.Id, null, tw.XmlData.OuterXml);
                    mi.AddAction(actAddTw);
                }

                baseOffset += padding;
            }

            if (destStraitLineWidget.IsLocked != isLocked)
            {
                Action actLock = new Action(destStraitLineWidget.MasterEditor.Id, destStraitLineWidget.Id,
                    destStraitLineWidget.GetType().Name, XmlTags.IsLockedTag, destStraitLineWidget.IsLocked.ToString(), isLocked.ToString());
                destStraitLineWidget.IsLocked = isLocked;
                mi.AddAction(actLock);
            }

            destStraitLineWidget.MasterEditor.MasterManager.RegisterModifingItem(mi);
        }

    }
}
